package uia.alumni.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import uia.alumni.data.Role;
import uia.alumni.data.User;
import uia.alumni.profile.Register;
import uia.alumni.profile.ViewProfile;
import uia.alumni.useradm.UserAdmin;



/**
 * The abstract Page class should be used as the superclass for all
 * commands that output html pages. This will enforce
 * a uniform look and feel across all html pages in the application.
 * <p>
 * Subclasses of this class must implement the writeBody() method.
 * <p>
 * This class produces pages consisting of a number of nested 
 * &lt;DIV&gt;-elements. The layout of these elements are controlled
 * by the stylesheet style.css. The ascii drawing below shows
 * the structure and the current layout.
 *
 * <pre>
 * +- wrapper ----------------------------------------------+
 * | +- banner ----------------------------+ +- loginbox--+ |
 * | |                                     | |            | |
 * | +-------------------------------------+ +------------+ |
 * | +- menu ----+ +- main -------------------------------+ |
 * | |           | | +- body ---------------------------+ | |
 * | |           | | |                                  | | |
 * | |           | | | content generated by writeBody() | | |
 * | |           | | |                                  | | |
 * | |           | | +----------------------------------+ | |
 * | |           | | +- message ------------------------+ | |
 * | |           | | |                                  | | |
 * | |           | | +----------------------------------+ | |
 * | + ----------+ +------------------------------------+ | |
 * +--------------------------------------------------------+
 * </pre>
 *
 * @author Even Aaby Larsen (even.larsen@uia.no)
 */
public abstract class Page extends  Command implements Constants {


    public Page(Role requiredRole) {
        super(requiredRole);
    }


    /**
     * Sets sensible headers before calling writeBody()
     *
     * @param request DOCUMENT ME!!
     * @throws IOException DOCUMENT WHEN!!
     */
    public void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Expires", "0");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        writeHeader(out, request);
        writeWrapper(out, request);
        writeEnd(out, request);

        /* Flushes and closes the out writer */
        out.flush();
        out.close();
    }


    /**
     * Writes the start of the page, the html headers and the menu
     */
    private void writeHeader(PrintWriter out, HttpServletRequest request) {
        out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">");
        out.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
        out.println("<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\" />");
        out.println("<meta name=\"generator\" content=\""+getClass().getName()+"\" />");
        out.println("<title>UiA Alumni</title>");
        out.println("<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"./style.css\" />");
        out.println("</head>");
        out.println("\n<body>");
    }


    private void writeWrapper(PrintWriter out, HttpServletRequest request) {
        out.println("<div id=\"wrapper\">");
        writeBanner(out, request);
        writeLoginBox(out, request);
        writeMenu(out, request);
        writeMain(out, request);
        out.println("\n</div> <!-- wrapper -->");
    }


    private void writeBanner(PrintWriter out, HttpServletRequest request) {
        out.println("\n<div id=\"banner\">UiA Alumni</div>");
    }


    /** writes the html code for the loginbox */
    private void writeLoginBox(PrintWriter out, HttpServletRequest request) {
        User user = (User)request.getSession().getAttribute(USER);

        out.println("\n<div id=\"loginbox\">");
        if (user == null) {
            out.println("<form action=\""+"login.do"
                    +"\" method=\"POST\" enctype=\"application/x-www-form-urlencoded\" name=\"login\">");
            out.println("<input name=\""+USERNAME+"\" type=\"text\" />"
                    +"<input name=\""+PASSWORD+"\" type=\"password\" /><input type=\"submit\" value=\"Logg inn\" />");
            out.println("</form>");
        }
        else {
            out.println("<p>Du er logget inn som <b>"+user.getUserName()+"</b><br/>");
            printLink(out, "Log out", Logout.SERVLET_NAME);
            out.println("</p>");
        }
        out.println("</div> <!-- loginbox -->");
    }


    /** Write the menu */
    protected void writeMenu(PrintWriter out, HttpServletRequest req) {
        out.println("\n<div id=\"menu\">");
        out.println("<ul>");
        out.print("<li>");
        printLink(out, "Home", Home.SERVLET_NAME);
        out.println("</li>");
        if (null == getLoggedInUser(null, req)) {
            out.print("<li>");
            printLink(out, "Register", Register.SERVLET_NAME);
            out.println("</li>");
        }
        if (isUserInRole(req, Role.member)) {
            out.println("<li>&nbsp;</li>");
            out.print("<li>");
            printLink(out, "My profile", ViewProfile.SERVLET_NAME);
            out.println("</li>");
            out.print("<li>");
            printLink(out, "Add member functions here", Home.SERVLET_NAME);
            out.println("</li>");
        }
        if (isUserInRole(req, Role.admin)) {
            out.println("<li>&nbsp;</li>");
            out.print("<li>");
            printLink(out, "User Administration", UserAdmin.SERVLET_NAME);
            out.println("</li>");
            out.print("<li>");
            printLink(out, "Add admin functions here", Home.SERVLET_NAME);
            out.println("</li>");
        }
        out.println("</ul>");
        out.println("</div> <!-- menu -->");
    }


    /** Write the content part of the page */
    private void writeMain(PrintWriter out, HttpServletRequest request) {
        out.println("\n<div id=\"main\">");
        out.println("\n<div id=\"body\">");
        writeBody(out, request);
        out.println("\n</div> <!-- body -->");
        writeMessage(out, request);
        out.println("\n</div> <!-- main -->");
    }


    /** Write any error or warning messages */
    private void writeMessage(PrintWriter out, HttpServletRequest request) {
        ArrayList<String> messages = (ArrayList<String>)request.getAttribute(MESSAGES);
        if (null != messages) {
            out.println("\n<div id=\"message\">");
            for (String msg : messages) {
                out.println("<p>"+msg+"</p>");
            }
            out.println("</div> <!-- message -->");
        }
    }


    /**
     * Write the html document. This method is called by format, and
     * is expected to write the html code for the main content div
     * to the the PrintWriter out.
     */
    public abstract void writeBody(PrintWriter out, HttpServletRequest request);


    /**
     * Method that writes the html code to complete the page.
     */
    private void writeEnd(PrintWriter out, HttpServletRequest request) {
        out.println("\n</body>");
        out.println("</html>");
    }


    /**
     * Print a hyperlink tag.
     * @param label the displayed text
     * @param url the url to link to
     * @param param the parameter name
     * @param value the parameter value
     */
    protected void printLink(PrintWriter out,
            String label, String cmd) {
        printLink(out, label, cmd, null, null, null, null);
    }

    protected void printLink(PrintWriter out,
            String label, String cmd,
            String param, String value) {
        printLink(out, label, cmd, param, value, null, null);
    }

    protected void printLink(PrintWriter out,
            String label, String cmd,
            String param, String value,
            String param2, String value2) {
        out.print("<a href=\"");
        out.print(cmd+".do");
        if (param != null) out.print("?"+param+"="+value);
        if (param2 != null) out.print("&amp;"+param2+"="+value2);
        out.print("\">");
        out.print(label);
        out.print("</a>");
    }


    /**
     * Print the opening tag for a form.
     */
    protected void printStartForm(PrintWriter out, String cmd) {
        out.print("<form action=\""+cmd+".do\" method=\"POST\" ");
        out.println("enctype=\"application/x-www-form-urlencoded\">");
    }

    
    /**
     * Print a text field with label as html table row.
     * @param label the field label. It is printed in the first column.
     * @param name the field name.
     * @param value the default field value */
    protected void printTextField(PrintWriter out,
            String label, String name, String value, boolean editable) {
        out.println("<tr>\n<td>"+label+":</td>");
        out.print("<td><input type=\"text\" name=\"" + name + "\" value=\"" + value + "\" ");
        if (! editable) out.print(" readonly ");
        out.println("/></td>\n</tr>\n");
    }


    /**
     * Print a text area with label as html table row.
     * @param label the field label. It is printed in the first column.
     * @param name the field name.
     * @param value the default field value */
    protected void printTextArea(PrintWriter out,
            String label, String name, String value, boolean editable) {
        out.println("<tr><td>"+label+":</td></tr>");
        out.println("<tr><td colspan=\"2\">");
        out.print("<textarea name=\""+name+"\" rows=\"5\" cols=\"60\">");
        out.print(value);
        out.println("</textarea></td></tr>\n");
    }


    /**
     * Print a check box
     */
    protected void printCheckBox(PrintWriter out,
            String label, String name, boolean checked) {
        out.println("<tr><td>" + label + ":</td>");
        out.print("<td><input type=\"checkbox\" name=\"" + name + "\" value=\"" + name + "\"");
        if (checked) out.print(" checked ");
        out.println("/></td></tr>\n");
    }


    /**
     * Print a password field with label as html table row.
     * @param label the field label. It is printed in the first column.
     * @param name the field name */
    protected void printPasswordField(PrintWriter out, String label, String name) {
        out.println("          <tr>\n            <td>");
        out.println("              " + label + ":\n            </td>");
        out.println("            <td>");
        out.println("              <input type=\"password\" name=\"" + name + "\" />");
        out.println("            </td>\n          </tr>\n");
    }


    /**
     * Print dropdown menu selectors for a date. The output is a table row with two cells.
     * The first cell contains the prompt. The second cell contains a select element for
     * day, month and year. The name of the day selector is prefix_d, the month selector
     * prefix_m, and year prefix_y.
     *
     * @param prompt
     * @param date pre-selected value
     * @param prefix prefix used to ensure that the select controls have unique names
     */
    protected void printDateSelector(PrintWriter out, String prompt, Date date, String prefix) {
        Calendar cal = getCalendar();
        if (date != null) cal.setTime(date);

        out.println("          <tr>\n            <td>"+prompt+":</td>");
        out.println("            <td>\n              <select name=\""+prefix+"_d\">");

        // day
        for (int d = 1; d<32; d++) {
            String dd = Integer.toString(d);
            if (d<10) dd = "0"+dd;
            out.print("              <option value=\""+dd+"\"");
            if (d == cal.get(Calendar.DAY_OF_MONTH)) out.print(" selected=\"selected\"");
            out.println(">"+dd+"</option>");
        }

        // month
        out.println("              </select>\n              <select name=\""+prefix+"_m\">");
        for (int m = 0; m<12; m++) {
            String mm = Integer.toString(m+1);
            if (m<9) mm = "0"+mm;
            out.print("              <option value=\""+m+"\"");
            if (m == cal.get(Calendar.MONTH)) out.print(" selected=\"selected\"");
            out.println(">"+mm+"</option>");
        }

        // year
        out.println("              </select>\n              <select name=\""+prefix+"_y\">");
        for (int y = 1960; y<2020; y++) {
            String yy = Integer.toString(y);
            out.print("              <option value=\""+yy+"\"");
            if (y == cal.get(Calendar.YEAR))out.print(" selected=\"selected\"");
            out.println(">"+yy+"</option>");
        }
        out.println("              </select>");
        out.println("            </td>");
        out.println("          <tr>");
    }


    private DateFormat dateFormat = null;

    protected String formatDate(Date date) {
        if (dateFormat == null) {
            dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
        }

        return dateFormat.format(date);
    }

    // useful stuff for handling dates
    /** The Calendar in use */
    private Calendar calendar;

    /** Get a Calendar */
    protected Calendar getCalendar() {
        if (calendar == null) calendar = Calendar.getInstance();
        return calendar;
    }
}
